package com.laicunba.service.jzh.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.laicunba.event.SellOutEvent;
import com.laicunba.pojo.BorrowerDO;
import com.laicunba.pojo.CashCouponDO;
import com.laicunba.pojo.FinancingTargetBidDO;
import com.laicunba.pojo.FinancingTargetDO;
import com.laicunba.pojo.JzhAccountDO;
import com.laicunba.pojo.JzhBidOrderDO;
import com.laicunba.pojo.RateIncrCouponDO;
import com.laicunba.pojo.UserDO;
import com.laicunba.service.AlertService;
import com.laicunba.service.BorrowerService;
import com.laicunba.service.CashCouponService;
import com.laicunba.service.FinancingTargetBidService;
import com.laicunba.service.FinancingTargetService;
import com.laicunba.service.RateIncrCouponService;
import com.laicunba.service.SaleService;
import com.laicunba.service.UserService;
import com.laicunba.service.exception.MyException;
import com.laicunba.service.impl.BaseServiceImpl;
import com.laicunba.service.jzh.JzhAccountService;
import com.laicunba.service.jzh.JzhBidOrderService;
import com.laicunba.service.jzh.JzhRemotePreAuthService;
import com.laicunba.service.jzh.JzhRemoteTransferBuService;
import com.laicunba.util.AssertUtil;
import com.laicunba.util.SeqUtil;
import com.laicunba.util.StringUtil;
import com.laicunba.util.ThreadUtil;

@Service
public class JzhBidOrderServiceImpl extends BaseServiceImpl implements JzhBidOrderService ,ApplicationEventPublisherAware{
	private static final Logger LOG = Logger.getLogger(JzhBidOrderServiceImpl.class);
	@Autowired
	private FinancingTargetService financingTargetService;
	@Autowired
	private UserService userService;
	@Autowired
	private JzhAccountService jzhAccountService;
	@Autowired
	private JzhRemotePreAuthService jzhRemotePreAuthService;
	@Autowired
	private BorrowerService borrowerService;
	@Autowired
	private CashCouponService cashCouponService;
	@Autowired
	private RateIncrCouponService rateIncrCouponService;
	@Autowired
	private FinancingTargetBidService financingTargetBidService;
	@Autowired
	private JzhRemoteTransferBuService jzhRemoteTransferBuService;
	@Autowired
	private SaleService saleService;
	private ApplicationEventPublisher applicationEventPublisher;
	@Autowired
	private AlertService  alertService;

	@Transactional
	@Override
	public BuyResult doPay(BuyParam param) {
		// verify param
		AssertUtil.assertNotNull(param, "param_null:参数为空");
		AssertUtil.assertNotEmpty(param.getUserId(), "USER_ID_NOT_EXIST:用户不存在");
		AssertUtil.assertNotEmpty(param.getFinancingTargetId(), "FINANCING_TARGET_ID_NOT_EXIST:标的不存在");
		AssertUtil.assertTrue(param.getBuyAmt() != null && param.getBuyAmt().compareTo(BigDecimal.ZERO) > 0, "AMT_LESS_ZERO:金额不正确");

		// verify financing target
		FinancingTargetDO financingTargetDO = financingTargetService.get(FinancingTargetDO.class, param.getFinancingTargetId());
		AssertUtil.assertNotNull(financingTargetDO, "FINANCING_TARGET_NOT_EXIST:标的不存在");
		AssertUtil.assertTrue("onsale".equalsIgnoreCase(financingTargetDO.getStatus()), "NOT_ONSALE:未上架");
		AssertUtil.assertNotEmpty(financingTargetDO.getBorrowerId(), "NO_BORROWER:没有借款人");
		AssertUtil.assertTrue(financingTargetDO.getCollectAmount() != null, "COLLECT_AMOUNT_ERROR");
		AssertUtil.assertTrue(financingTargetDO.getCollectAmount().subtract(financingTargetDO.getFinishAmount()).compareTo(param.getBuyAmt()) >= 0, "COLLECT_AMOUNT_NOT_ENOUGH");
		AssertUtil.assertTrue((financingTargetDO.getLimitAmount() == null) || financingTargetDO.getLimitAmount().compareTo(BigDecimal.ZERO) == 0
				|| financingTargetDO.getLimitAmount().compareTo(param.getBuyAmt()) >= 0, "MORE_THEN_LIMIT");
		AssertUtil.assertTrue(financingTargetDO.getBeginDate() != null && financingTargetDO.getBeginDate().getTime() < System.currentTimeMillis(), "NOT_BEGIN_SALE:未开售");
		AssertUtil.assertTrue(param.getBuyAmt().compareTo(financingTargetDO.getMinAmount()) >= 0, "LESS_THEN_MIN:少于最低购买份额");

		// verify buyer
		UserDO buyer = userService.get(UserDO.class, param.getUserId());
		AssertUtil.assertNotNull(buyer, "BUYER_NOT_EXIST:买家不存在");
		AssertUtil.assertTrue("enable".equalsIgnoreCase(buyer.getJzhStatus()), "NOT_ENABLE_JZH_ACCOUNT:未开通存管");
		AssertUtil.assertTrue("enable".equalsIgnoreCase(buyer.getStatus()) || StringUtil.isEmpty(buyer.getStatus()), "USER_STOP_TRADE:用户暂不可交易");
		// verify jzh account
		JzhAccountDO jzhAccountDO = jzhAccountService.get(JzhAccountDO.class, buyer.getId());
		AssertUtil.assertNotNull(jzhAccountDO, "NOT_ENABLE_JZH_ACCOUNT_02:未开通存管");
		AssertUtil.assertTrue(jzhAccountDO.getBalance() != null, "BALANCE_ERROR:余额错误");
		AssertUtil.assertTrue(jzhAccountDO.getBalance().compareTo(param.getBuyAmt()) >= 0, "BALANCE_NOT_ENOUGH:余额不足");

		// verify borrower
		BorrowerDO borrowerDO = borrowerService.get(BorrowerDO.class, financingTargetDO.getBorrowerId());
		AssertUtil.assertNotNull(borrowerDO, "BORROWER_NOT_EXIST:借款人不存在");

		CashCouponDO cashCouponDO = null;
		// 检查现金券
		if (StringUtil.isNotEmpty(param.getCashCouponId())) {
			cashCouponDO = cashCouponService.get(CashCouponDO.class, param.getCashCouponId());

			// 检查现金券条件
			AssertUtil.assertTrue(cashCouponService.testForConditions(cashCouponDO, buyer, financingTargetDO, param.getBuyAmt()));
		}

		RateIncrCouponDO rateIncrCouponDO = null;
		// 检查加息券
		if (StringUtil.isNotEmpty(param.getRateIncrCouponId())) {
			rateIncrCouponDO = rateIncrCouponService.get(RateIncrCouponDO.class, param.getRateIncrCouponId());
			// 检查现加息条件
			AssertUtil.assertTrue(rateIncrCouponService.testForConditions(rateIncrCouponDO, buyer, financingTargetDO, param.getBuyAmt()));
		}

		// 存管预授权接口
		String mchntTxnSsn = "PA" + Long.toString(System.currentTimeMillis()) + StringUtil.randomNumber(5) + String.format("%06d", param.getSeq());
		JzhRemotePreAuthService.Param preAuthParam = new JzhRemotePreAuthService.Param();
		preAuthParam.setCentAmt(param.getBuyAmt().multiply(BigDecimal.valueOf(100)).longValue());
		preAuthParam.setMchntTxnSsn(mchntTxnSsn);
		preAuthParam.setRem(param.getUserId());
		preAuthParam.setOutCustNo(jzhAccountDO.getMobileNo());
		preAuthParam.setInCustNo(borrowerDO.getMobile());
		JzhRemotePreAuthService.Result preAuthResult = jzhRemotePreAuthService.post(preAuthParam);
		AssertUtil.assertNotNull(preAuthResult, "PRE_AUTH_RESULT_IS_NULL:预授权结果为空");
		AssertUtil.assertTrue("0000".equals(preAuthResult.getRespCode()), preAuthResult.getRespCode() + ":" + preAuthResult.getRespDesc());
		// 处理现金券
		String orderId = buyer.getId() + "_" + preAuthResult.getContractNo();
		if (cashCouponDO != null) {
			cashCouponDO.setUsedAmount(cashCouponDO.getAmount());
			cashCouponDO.setSummary(orderId);
			AssertUtil.assertTrue(cashCouponService.updateSkipCheckOwner(cashCouponDO), "UPDATE_CASH_COUPON_DO_FAIL:更新现金券失败");
		}
		// 处理加息券
		if (rateIncrCouponDO != null) {
			rateIncrCouponDO.setStatus("used");
			rateIncrCouponDO.setSummary(orderId);
			AssertUtil.assertTrue(rateIncrCouponService.updateSkipCheckOwner(rateIncrCouponDO), "UPDATE_RATE_COUPON_DO_FAIL:更新加息券失败");
		}
		// 扣掉本地的钱
		AssertUtil.assertTrue(jzhAccountService.subtract(buyer.getId(), param.getBuyAmt(), orderId, "bid_order", "购买标的") != null, "SUBTRACT_JZH_ACCOUNT_FAIL:扣款失败");
		// 购买标的
		JzhBidOrderDO orderDO = new JzhBidOrderDO();
		orderDO.setBidUserId(buyer.getId());
		orderDO.setBuyAmount(param.getBuyAmt());
		orderDO.setCashCouponId(param.getCashCouponId());
		orderDO.setContractNo(preAuthResult.getContractNo());
		orderDO.setId(orderId);
		orderDO.setFinancingTargetId(financingTargetDO.getId());
		orderDO.setMchntTxnSsn(mchntTxnSsn);
		orderDO.setPay(true);
		orderDO.setRateIncrCouponId(param.getRateIncrCouponId());
		orderDO.setRate(financingTargetDO.getAnnualizedRates());
		orderDO.setTransferCurrent(param.isTransferCurrent());
		orderDO.setStatus("new");
		orderDO.setOutCustNo(preAuthParam.getOutCustNo());
		orderDO.setInCustNo(preAuthParam.getInCustNo()); 
		orderDO.setSeq(SeqUtil.formatBidSeqNumber(param.getSeq()));
		AssertUtil.assertTrue(create(orderDO), "CREATE_BID_ORDER_FAIL:创建订单错误");
		// 减去库存
		AssertUtil.assertTrue(financingTargetService.subtractStock(financingTargetDO.getId(), param.getBuyAmt()), "SUBTRACT_STOCK_FAIL:减少库存失败");
		try {
			if (financingTargetDO.getCollectAmount().subtract(financingTargetDO.getFinishAmount() != null ? financingTargetDO.getFinishAmount() : BigDecimal.ZERO).subtract(param.getBuyAmt()).compareTo(BigDecimal.valueOf(1000)) < 0) {
				// 库存小于1000发预警信号
				final String targetId = financingTargetDO.getId();
				ThreadUtil.execute(new Runnable() {

					@Override
					public void run() {
						SellOutEvent event = new SellOutEvent(targetId);
						applicationEventPublisher.publishEvent(event);
					}
				});
			}
		} catch (Exception e) {
			alertService.error(null, String.format("%s天期的标的已售完,但无候选标,未自动上架成功!", financingTargetDO.getPeriod()));
			LOG.error("发出库存不足预警,处理出错", e);
		}
		// 付款（本来应该满标付款，因为支付方没做任何限制，我们暂时采用不满标付款方式）
		FinancingTargetBidDO bidDO = this.makeLoans(orderDO.getId());

		BuyResult result = new BuyResult();
		result.setOrder(orderDO);
		result.setBidDO(bidDO);
		return result;
	}

	@Override
	public List<String> findNewStatus(String financingTargetId) {
		return queryDao.selectList("JZH_BID_ORDER.findNewStatus", financingTargetId);
	}

	@Transactional
	@Override
	public FinancingTargetBidDO makeLoans(String bidOrderId) {
		JzhBidOrderDO orderDO = get(JzhBidOrderDO.class, bidOrderId);
		AssertUtil.assertNotNull(orderDO, "ORDER_DO_NULL:订单不存在");
		AssertUtil.assertTrue("new".equalsIgnoreCase(orderDO.getStatus()), "ORDER_NOT_NEW:订单状态不为new");
		AssertUtil.assertTrue(orderDO.isPay(), "ORDER_NOT_PAY:订单未支付");
		FinancingTargetBidDO financingTargetBidDO = financingTargetBidService.get(FinancingTargetBidDO.class, orderDO.getId());
		AssertUtil.assertTrue(financingTargetBidDO == null, "BID_DO_EXIST:订单重复处理");
		FinancingTargetDO financingTargetDO = financingTargetService.get(FinancingTargetDO.class, orderDO.getFinancingTargetId());
		AssertUtil.assertNotNull(financingTargetDO, "FINANCING_TARGET_DO_NOT_EXIST:标的不存在");
		// AssertUtil.assertTrue("CPB".equalsIgnoreCase(financingTargetDO.getType()),
		// "NOT_CPB:不是定标");
		// 放款
		JzhRemoteTransferBuService.Param param = new JzhRemoteTransferBuService.Param();
		param.setCentAmt(orderDO.getBuyAmount().multiply(BigDecimal.valueOf(100)).longValue());
		param.setContractNo(orderDO.getContractNo());
		param.setRem("");
		param.setInCustNo(orderDO.getInCustNo());
		param.setOutCustNo(orderDO.getOutCustNo());
		param.setMchntTxnSsn(orderDO.getContractNo() + "_" + System.currentTimeMillis());
		JzhRemoteTransferBuService.Result result = jzhRemoteTransferBuService.post(param);
		AssertUtil.assertNotNull(result, "RESULT_NULL:放款失败");
		AssertUtil.assertTrue("0000".equals(result.getRespCode()) || "3122".equals(result.getRespCode()), result.getRespCode() + ":" + result.getRespDesc());
		// 生成下单数据
		AssertUtil.assertTrue(this.updateDao.update("JZH_BID_ORDER.updateFinishStatus", bidOrderId) == 1, "update_finish_status_fail:更新完成状态失败");

		// 生成投标数据
		FinancingTargetBidDO bidDO = new FinancingTargetBidDO();
		bidDO.setSeq(orderDO.getSeq());
		bidDO.setAnnualizedRates(orderDO.getRate());
		bidDO.setBidUserId(orderDO.getBidUserId());
		bidDO.setBuyAmount(orderDO.getBuyAmount());
		bidDO.setFinancingTargetId(orderDO.getFinancingTargetId());
		bidDO.setCertificateId(param.getMchntTxnSsn());
		bidDO.setId(orderDO.getId());
		bidDO.setType(financingTargetDO.getType());
		bidDO.setPay(true);
		bidDO.setPayTime(orderDO.getGmtCreate());
		bidDO.setPayMark("JZH");
		bidDO.setWithdrawPrincipal(BigDecimal.ZERO);
		bidDO.setWithdrawProfit(BigDecimal.ZERO);
		bidDO.setTransferCurrent(orderDO.isTransferCurrent());
		// beginProfit
		bidDO.setBeginProfit(new Date());
		bidDO.getBeginProfit().setHours(0);
		bidDO.getBeginProfit().setMinutes(0);
		bidDO.getBeginProfit().setSeconds(0);
		bidDO.getBeginProfit().setDate(bidDO.getBeginProfit().getDate()+1);
		// endProfit
		Date endProfit = new Date(bidDO.getBeginProfit().getTime());
		endProfit.setDate(endProfit.getDate() + financingTargetDO.getPeriod());
		bidDO.setEndProfit(endProfit);
		//处理现金券
		if(StringUtil.isNotEmpty(orderDO.getCashCouponId())){
			CashCouponDO cashCouponDO = cashCouponService.get(CashCouponDO.class, orderDO.getCashCouponId()); 
			bidDO.setCashCouponId(cashCouponDO.getId());
			if(cashCouponDO.isAddProfit()){
				bidDO.setExpireSendProfit(cashCouponDO.getAmount());
			}else{
				bidDO.setBuyAmount(bidDO.getBuyAmount().add(cashCouponDO.getAmount()));
				bidDO.setCashCouponAmount(cashCouponDO.getAmount());
			}
		}
		//处理加息券
		if(StringUtil.isNotEmpty(orderDO.getRateIncrCouponId())){
			RateIncrCouponDO  rateIncrCouponDO = rateIncrCouponService.get(RateIncrCouponDO.class, orderDO.getRateIncrCouponId());
			bidDO.setRateIncrCouponId(rateIncrCouponDO.getId());
			bidDO.setAnnualizedRates(bidDO.getAnnualizedRates().add(rateIncrCouponDO.getRate()));
		}
		AssertUtil.assertTrue(financingTargetBidService.create(bidDO), "CREATE_BID_DO_FAIL:创建投标数据失败");
		if("SCB".equalsIgnoreCase(bidDO.getType())){ 
			saleService.transferBidToCurrentAccount(bidDO.getId());
		}
		return bidDO;
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
		
	}
 
}
